'/
' MOTEP - Massive Online Text Environment Project
' --------------------------------------------------------------------------------
' MOTEP Server
' 
' Master.bmx
' 
' (c) Anton Berlin. All Rights Reserved.
'/

' The master object. This is where everything happens. Only one instance
' of this object is possible.
type TMaster
	global consoleCommand:string
	global commandList:TList = CreateList()
	global instances:int = 0
	
	field m_stopEvent:byte = false
	field m_initiated:byte = false
	
	' Main method - this gets executed every frame.
	method Run()
		if (m_initiated) then
			' Receive the next packet.
			local packet:TRKPacket = serverPeer.Receive()
			if (packet) then
				local data:string = string.FromCString(packet.GetData())
				local msgType:int = packet.GetPacketIdentifier()
				local senderAddr:TRKSystemAddress = packet.GetSystemAddress()
				local senderPort:string = senderAddr.GetPort()
				local senderIndex:int = serverPeer.GetIndexFromSystemAddress(packet.GetSystemAddress())
				
				select (msgType)
					case ID_CONNECTION_REQUEST_ACCEPTED
						write("Server created successfully. Starting to listen for connections (port " + serverPort + ").")
						write("Press <ESCAPE> or enter ~qquit~q to exit.")
						masterAddr = senderAddr
						sendMessageToMaster(INFO_SERVER_NAME, 0, ID_INFO)
					case ID_CONNECTION_ATTEMPT_FAILED
						write("Could not connect to master server.")
						renderFrame()
						Return 0
					case ID_NEW_INCOMING_CONNECTION
						write("Client " + senderIndex + " connected from " + senderAddr.ToString() + ".")
					case ID_DISCONNECTION_NOTIFICATION
						write("Client " + senderIndex + " disconnected.")
					case ID_CONNECTION_LOST
						if (serverPeer.IsLocalIP(senderAddr.ToString())) ..
							write("Lost connection to master server.") ..
						else ..
							write("Client " + senderIndex + " lost the connection.")
					case ID_MODIFIED_PACKET
						write("WARNING: Received modified packet from " + senderAddr.ToString() + "!")
						serverPeer.CloseConnection(senderAddr, 1)
						write("Connection kicked.")
					default
						local kind:string = str.word(0, data)
						select kind
							case ID_COMMAND
							case ID_QUERY
								local query:string = str.word(1, data)
								local args:string
								
								for local i:int = 2 until str.words(data)
									if (args) then
										args = args + " " + str.word(i, data)
									else
										args = str.word(i, data)
									end if
								next
								
								select (query)
									case QUERY_SERVER_CHARACTERS_LIST
										write("Sending character-list to " + senderAddr.ToString() + ".")
										sendMessageToPeer(serverPeer, ID_LISTSTART + " " + LIST_SERVER_CHARACTERS, 0, senderAddr)
										for local str:String = eachin GetCharList(GlobalCharMap, arg(args, 1))
											sendMessageToPeer(serverPeer, ID_LISTDATA + " " + LIST_SERVER_CHARACTERS + " " + str, 0, senderAddr)
										next
										sendMessageToPeer(serverPeer, ID_LISTEND + " " + LIST_SERVER_CHARACTERS, 0, senderAddr)
								end select
						end select
				end select
				
				serverPeer.DeallocatePacket(packet)
			end if
			
			handleConsole()
			renderFrame()
		end if
	end method
	
	' Initialize the master.
	method Initialize:byte()
		if (instances > 0) return 0
		instances:+1
		m_initiated = true
		return 1
	end method
	
	' Handle the console.
	function handleConsole()
		gatherCommands()
		consoleCommand = consoleInput()
		if (not handleCmds(consoleCommand)) ..
			write("Unknown command.")
		consoleCommand = null
	end function
	
	' Gather commands.
	function gatherCommands()
		ClearList(commandList)
		ListAddLast(commandList, new cmd_quit)
		'ListAddLast(commandList, new cmd_look)
		'ListAddLast(commandList, new cmd_pos)
	end function
end type



' Extract a specific argument from a message.
function arg:string(args:string, a:int)
	if (a < 1) return null
	return str.word(a - 1, args)
end function
